    /*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package db.xml;

import core.Book;
import core.Course;
import core.Program;
import core.School;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

/**
 * The Class is used for retrieving School object tree via XML/HTTP
 * School contain a tree of program, courses and books.
 * The class relies on XSD files: programListXmlSchema.xsd, bookListXmlSchema.xsd,
 * bookXmlSchema.xsd, courseXmlSchema.xsd, courseListXmlSchema.xsd,
 * programXmlSchema.xsd and schoolXmlSchema.xsd to validate the XML source.
 * 
 * @author Peter
 */
public class SchoolXMLDAO {

    // path to xsd files
    private static final String XSD_programList = "schema/programListXmlSchema.xsd";
    private static final String XSD_bookList = "schema/bookListXmlSchema.xsd";
    private static final String XSD_book = "schema/bookXmlSchema.xsd";
    private static final String XSD_course = "schema/courseXmlSchema.xsd";
    private static final String XSD_courseList = "schema/courseListXmlSchema.xsd";
    private static final String XSD_program = "schema/programXmlSchema.xsd";
    private static final String XSD_school = "schema/schoolXmlSchema.xsd";
    // theese relies entierly on the xsd schema files!
    int XML_SCHOOL_ELEMENT_name = 0;
    int XML_SCHOOL_ELEMENT_description = 1;
    int XML_SCHOOL_ELEMENT_link = 2;
    int XML_SCHOOL_ELEMENT_programs = 3;
    int XML_SCHOOL_ELEMENT_courses = 4;
    int XML_PROGRAM_ELEMENT_name = 0;
    int XML_PROGRAM_ELEMENT_description = 1;
    int XML_PROGRAM_ELEMENT_link = 2;
    int XML_PROGRAM_ELEMENT_programId = 3;
    int XML_PROGRAM_ELEMENT_courses = 4;
    int XML_COURSE_ELEMENT_name = 0;
    int XML_COURSE_ELEMENT_description = 1;
    int XML_COURSE_ELEMENT_link = 2;
    int XML_COURSE_ELEMENT_courseId = 3;
    int XML_COURSE_ELEMENT_books = 4;


    /**
     * help function to validate XML source
     * @param xmlUrlString
     * @return
     */
    private boolean validateSchool(String xmlUrlString) {
        String[] xsdFilez = {
            XSD_book,
            XSD_bookList,
            XSD_course,
            XSD_courseList,
            XSD_program,
            XSD_programList,
            XSD_school
        };

        Source[] xsdFiles = {
            new StreamSource
                    (this.getClass().getResourceAsStream(XSD_book)),
            new StreamSource
                    (this.getClass().getResourceAsStream(XSD_bookList)),
            new StreamSource
                    (this.getClass().getResourceAsStream(XSD_course)),
            new StreamSource
                    (this.getClass().getResourceAsStream(XSD_courseList)),
            new StreamSource
                    (this.getClass().getResourceAsStream(XSD_program)),
            new StreamSource
                    (this.getClass().getResourceAsStream(XSD_programList)),
            new StreamSource
                    (this.getClass().getResourceAsStream(XSD_school))
            };

        URL xmlUrl;
        try {
            xmlUrl = new URL(xmlUrlString);
        } catch (MalformedURLException ex) {
            System.out.println(ex.getMessage());
            return false;
        }
        if (!XmlUtils.validateXML(xsdFiles, xmlUrl)) {
            return false;
        }
        return true;


    }

    /**
     * Gets a school object of XML source (url)
     * @param xmlUrlString i.e. (http://www.school.com/xmlSource.php)
     * @return School object on success, otherwise null
     */
    public School getSchoolByURL(String xmlUrlString) {


        if (!validateSchool(xmlUrlString)) {
            return null;
        }

        Element root = getRootElement(xmlUrlString);
        if (root != null) {
            return parseSchool(root);
        }

        return null;
    }

    /**
     * gets the root element of a document fetched by URL
     * @param url
     * @return Element on success, otherwise null
     */
    private Element getRootElement(String url) {
        Element root = null;
        SAXBuilder parser = new SAXBuilder();

        try {

            Document doc = parser.build(url);
            root = doc.getRootElement();

        } catch (Exception ex) {
            return null; // return null for both Exception!
        }
        return root;
    }

    /**
     * private help method
     * @param rootElement
     * @return school object
     */
    private School parseSchool(Element rootElement) {
        List<Element> schoolElements = rootElement.getChildren();

        return new School(0,
                schoolElements.get(XML_SCHOOL_ELEMENT_name).getValue(),
                schoolElements.get(XML_SCHOOL_ELEMENT_description).getValue(),
                schoolElements.get(XML_SCHOOL_ELEMENT_link).getValue(),
                null,
                parsePrograms(schoolElements.get(XML_SCHOOL_ELEMENT_programs)),
                parseCourses(schoolElements.get(XML_SCHOOL_ELEMENT_courses)));

    }

    /**
     * help method
     * @param programListRoot
     * @return
     */
    private List<Program> parsePrograms(Element programListRoot) {
        List<Program> programs = new ArrayList<Program>();
        List<Element> programList = programListRoot.getChildren();
        for (Element program : programList) {
            programs.add(parseProgram(program));
        }
        return programs;

    }

    /**
     * help method
     * @param programRoot
     * @return
     */
    private Program parseProgram(Element programRoot) {
        List<Element> programElements = programRoot.getChildren();
        return new Program(0,
                programElements.get(XML_PROGRAM_ELEMENT_name).getValue(),
                programElements.get(XML_PROGRAM_ELEMENT_description).getValue(),
                programElements.get(XML_PROGRAM_ELEMENT_link).getValue(),
                programElements.get(XML_PROGRAM_ELEMENT_programId).getValue(),
                parseCourses(programElements.get(XML_PROGRAM_ELEMENT_courses)));
    }

    /**
     * help method
     * @param CourseListRoot
     * @return
     */
    private List<Course> parseCourses(Element CourseListRoot) {
        List<Course> courses = new ArrayList<Course>();
        List<Element> courseList = CourseListRoot.getChildren();
        for (Element course : courseList) {
            courses.add(parseCourse(course));
        }
        return courses;
    }

    /**
     * help method
     * @param courseRoot
     * @return Course
     */
    private Course parseCourse(Element courseRoot) {
        List<Element> programElements = courseRoot.getChildren();
        return new Course(0,
                programElements.get(XML_COURSE_ELEMENT_name).getValue(),
                programElements.get(XML_COURSE_ELEMENT_description).getValue(),
                programElements.get(XML_COURSE_ELEMENT_link).getValue(),
                programElements.get(XML_COURSE_ELEMENT_courseId).getValue(),
                parseBooks(programElements.get(XML_PROGRAM_ELEMENT_courses)));
    }

    /**
     * help method, relies on BookXML.getBook()
     * @param bookListRoot
     * @return List<Book>
     */
    private List<Book> parseBooks(Element bookListRoot) {
        List<Book> courses = new ArrayList<Book>();
        List<Element> bookList = bookListRoot.getChildren();
        for (Element book : bookList) {
            courses.add(BookXML.parseBook(book));
        }
        return courses;
    }
}

